package com.jacksay.vikingfl.synchro
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	import mx.core.UIComponent;
	
	[DefaultProperty("pipes")]
	
	public class VOSynchronizer implements IEventDispatcher
	{
		
		// ------------------------------------------------------------------
		// pipes
		// ------------------------------------------------------------------
		/**
		 * Pipes de configuration. Etabli une relation entre un composant de 
		 * l'interface et une propriété d'un Objet de donnée. Les Pipes 
		 * conditionnent la création d'écouteurs dans la vue pour surveiller 
		 * les modifications des données par l'utilisateur.
		 *
		 * @default null
		 * @see VOPipe
		 */
		[Inspectable(category="Other", defaultValue=null, type="Array")]
		[ArrayElementType("com.jacksay.vikingfl.synchro.VOPipe")]
		public function get pipes() :Array {
			return _pipes;
		}
		
		/**
		 * @private
		 */
		private var _pipes:Array = null;
		
		/**
		 * @private
		 */
		public function set pipes( value:Array ) :void {
			_pipes = value;
		}
		
		
		
		// ------------------------------------------------------------------
		// initialVO
		// ------------------------------------------------------------------
		private var _userVO:*;

		
		private var dispatcher:EventDispatcher;
		
		public function VOSynchronizer(pipes:Array=null)
		{
			dispatcher = new EventDispatcher(this);
			pipes = pipes;
		}
		
		// -----------------------------------------------------------------------------
		// hasUserChange
		// -----------------------------------------------------------------------------
		/**
		 * Si des modifications utilisateurs ont eut lieu, retourne <code>true</code> sinon retourne <code>false</code>
		 * 
		 * @default false
		 * @author jacksay14
		 * @date 2009-12-15
		 */ 
		[Inspectable(defaultValue=false,verbose=1,category=Other,type=Boolean,enumeration=true,false)]
		[Bindable("synchroUserChange")]
		public function get hasUserChange () :Boolean{
			return _hasUserChange;
		}
		
		/**
		 * @private
		 */
		private var _hasUserChange:Boolean = false;


		
		private var fVOInitialized:Boolean = false;
		/** 
		 * Définit la donnée de référence sur laquelle le VOSynchronizer va s'
		 * appuyer pour effectuer les comparaisons de valeur.
		 */
		public function initVO( vo:* ) :void {
			_userVO = vo;
			fVOInitialized = true;
			
			var properties:Array;
			var pipe:VOPipe;
			var pipeProperty:VOPipeProperty;
			
			for each( pipe in pipes ){
				for each( pipeProperty in pipe.properties ){
					pipeProperty.initInitialData( vo[pipeProperty.dataNameInVO] );
				}
			}
		}
		
		
		private var fPipiesInitialized:Boolean = false;
		
		/**
		 * Consruction du systèm d'écoute sur la vue pour la synchro des 
		 * données.
		 */
		public function initPipes() :void {
			
			var properties:Array;
			var pipe:VOPipe;
			var pipeProperty:VOPipeProperty;
			
			for each( pipe in pipes ){
				for each( pipeProperty in pipe.properties ){
					pipe.host.addEventListener(pipeProperty.dataEventInHost, hostChange, false, 0, true);
				}
			}
		}
		
		protected function getPipeByHost( host:UIComponent ) :VOPipe {
			var pipe:VOPipe;
			for each( pipe in pipes ){
				if( host == pipe.host ){
					return pipe;
				}
			}
			throw new Error("Host introuvable");
		}
		
		protected function hostChange( e:Event ) :void {
			var host:UIComponent = UIComponent(e.currentTarget);
			var pipe:VOPipe = getPipeByHost(host);
			pipe.initUserData();
			refreshHasUserChange();
		}
		
		
		protected function refreshHasUserChange() :void {
			var pipe:VOPipe;
			var pipeProperty:VOPipeProperty;
			for each( pipe in pipes ){
				for each( pipeProperty in pipe.properties ){
					if( pipeProperty.hasUserChange() ){
						_hasUserChange = true;
						dispatchEvent(new VOSynchronizerEvent(VOSynchronizerEvent.SYNCHRO_USER_CHANGE));
						return;
					} 
				}
			}
			_hasUserChange = false;
			dispatchEvent(new VOSynchronizerEvent(VOSynchronizerEvent.SYNCHRO_USER_CHANGE));
		}
		
		
		public function get userVO() :* {
			// var vo:* = ObjectUtil.copy(initialVO);
			var pipe:VOPipe;
			var pipeProperty:VOPipeProperty;
			for each( pipe in pipes ){
				for each( pipeProperty in pipe.properties ){
					_userVO[pipeProperty.dataNameInVO] = pipeProperty.userData;
				}
			}
			return _userVO;
		}
		
		
		public function synchronize( value:* ) :void {
			
			var pipe:VOPipe;
			var needRefresh:Boolean = false;
			var repportsModal:Array = [];
			var repport:VOSynchonizePipeRepport;
			
			for each( pipe in pipes ){
				repport = pipe.synchronize(value);
				if( repport.response > 2 ){
					repportsModal.push(repport);
				} 
				if( repport.response > 1 ){
					needRefresh = true;
				}
			}
			
			if( repportsModal.length > 0 ){
				trace("Modal requis");
				VOModalSynchro.show(repportsModal, onResolve);
			} else if( needRefresh ){
				trace("Simple refresh");
				dispatchEvent(new VOSynchronizerEvent(VOSynchronizerEvent.SYNCHRO_COMPLETE));
			} else {
				trace("Rien à changer");
			}
		}
		
		protected function onResolve() :void {
			dispatchEvent(new VOSynchronizerEvent(VOSynchronizerEvent.SYNCHRO_COMPLETE));
		}
		
		
		

		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);	
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return dispatcher.dispatchEvent(event);
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return dispatcher.hasEventListener(type);
		}
		
		public function willTrigger(type:String):Boolean
		{
			return dispatcher.willTrigger(type);
		}
		
	}
}